/*
 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "input/camera_manager_napi.h"

#include <cstddef>
#include <cstdint>
#include <mutex>
#include <string>
#include <unordered_map>
#include <utility>
#include <uv.h>

#include "camera_device.h"
#include "camera_error_code.h"
#include "camera_log.h"
#include "camera_manager.h"
#include "camera_napi_const.h"
#include "camera_napi_event_emitter.h"
#include "camera_napi_object_types.h"
#include "camera_napi_param_parser.h"
#include "camera_napi_security_utils.h"
#include "camera_napi_template_utils.h"
#include "camera_napi_utils.h"
#include "camera_output_capability.h"
#include "camera_xcollie.h"
#include "capture_scene_const.h"
#include "input/camera_napi.h"
#include "input/prelaunch_config.h"
#include "js_native_api.h"
#include "js_native_api_types.h"
#include "mode/aperture_video_session_napi.h"
#include "mode/fluorescence_photo_session_napi.h"
#include "mode/high_res_photo_session_napi.h"
#include "mode/light_painting_session_napi.h"
#include "mode/macro_photo_session_napi.h"
#include "mode/macro_video_session_napi.h"
#include "mode/night_session_napi.h"
#include "mode/photo_session_for_sys_napi.h"
#include "mode/photo_session_napi.h"
#include "mode/portrait_session_napi.h"
#include "mode/profession_session_napi.h"
#include "mode/quick_shot_photo_session_napi.h"
#include "mode/secure_camera_session_napi.h"
#include "mode/slow_motion_session_napi.h"
#include "mode/time_lapse_photo_session_napi.h"
#include "mode/video_session_for_sys_napi.h"
#include "mode/video_session_napi.h"
#include "napi/native_common.h"
#include "refbase.h"

namespace OHOS {
namespace CameraStandard {
namespace {
thread_local std::unordered_map<std::string, napi_ref> g_napiValueCacheMap {};
void CacheNapiValue(napi_env env, const std::string& key, napi_value value)
{
    napi_ref ref;
    napi_status status = napi_create_reference(env, value, 0, &ref); // 0 is weakref.
    if (status == napi_ok) {
        g_napiValueCacheMap[key] = ref;
        MEDIA_DEBUG_LOG("CacheNapiValue cache->%{public}s", key.c_str());
    }
}

napi_value GetCacheNapiValue(napi_env env, const std::string& key)
{
    napi_ref ref;
    auto it = g_napiValueCacheMap.find(key);
    if (it == g_napiValueCacheMap.end()) {
        return nullptr;
    }
    ref = it->second;
    napi_value result;
    napi_status status = napi_get_reference_value(env, ref, &result);
    if (status == napi_ok) {
        MEDIA_DEBUG_LOG("GetCacheNapiValue hit cache->%{public}s", key.c_str());
        return result;
    }
    return nullptr;
}

void CacheSupportedOutputCapability(napi_env env, const std::string& cameraId, int32_t mode, napi_value value)
{
    std::string key = "OutputCapability:" + cameraId + ":\t" + to_string(mode);
    CacheNapiValue(env, key, value);
    MEDIA_DEBUG_LOG("CacheSupportedOutputCapability cache->%{public}s:%{public}d", key.c_str(), mode);
}

napi_value GetCachedSupportedOutputCapability(napi_env env, const std::string& cameraId, int32_t mode)
{
    std::string key = "OutputCapability:" + cameraId + ":\t" + to_string(mode);
    napi_value result = GetCacheNapiValue(env, key);
    if (result != nullptr) {
        MEDIA_DEBUG_LOG("GetCachedSupportedOutputCapability hit cache->%{public}s:%{public}d", key.c_str(), mode);
    }
    return result;
}

void CacheSupportedCameras(napi_env env, const std::vector<sptr<CameraDevice>>& cameras, napi_value value)
{
    std::string key = "SupportedCameras:";
    for (auto& camera : cameras) {
        if (camera->GetConnectionType() != CAMERA_CONNECTION_BUILT_IN) {
            // Exist none built_in camera. Give up cache.
            MEDIA_DEBUG_LOG("CacheSupportedCameras exist none built_in camera. Give up cache");
            return;
        }
        key.append("\t:");
        key.append(camera->GetID());
    }
    CacheNapiValue(env, key, value);
    MEDIA_DEBUG_LOG("CacheSupportedCameras cache->%{public}s", key.c_str());
}

napi_value GetCachedSupportedCameras(napi_env env, const std::vector<sptr<CameraDevice>>& cameras)
{
    std::string key = "SupportedCameras:";
    for (auto& camera : cameras) {
        if (camera->GetConnectionType() != CAMERA_CONNECTION_BUILT_IN) {
            // Exist none built_in camera. Give up cache.
            MEDIA_DEBUG_LOG("GetCachedSupportedCameras exist none built_in camera. Give up cache");
            return nullptr;
        }
        key.append("\t:");
        key.append(camera->GetID());
    }
    napi_value result = GetCacheNapiValue(env, key);
    if (result != nullptr) {
        MEDIA_DEBUG_LOG("GetCachedSupportedCameras hit cache->%{public}s", key.c_str());
    }
    return result;
}
} // namespace

using namespace std;
using namespace CameraNapiSecurity;
thread_local napi_ref CameraManagerNapi::sConstructor_ = nullptr;
thread_local uint32_t CameraManagerNapi::cameraManagerTaskId = CAMERA_MANAGER_TASKID;

const std::unordered_map<SceneMode, JsSceneMode> g_nativeToNapiSupportedModeForSystem_ = {
    {SceneMode::CAPTURE,  JsSceneMode::JS_CAPTURE},
    {SceneMode::VIDEO,  JsSceneMode::JS_VIDEO},
    {SceneMode::PORTRAIT,  JsSceneMode::JS_PORTRAIT},
    {SceneMode::NIGHT,  JsSceneMode::JS_NIGHT},
    {SceneMode::CAPTURE_MACRO, JsSceneMode::JS_CAPTURE_MARCO},
    {SceneMode::VIDEO_MACRO, JsSceneMode::JS_VIDEO_MARCO},
    {SceneMode::SLOW_MOTION,  JsSceneMode::JS_SLOW_MOTION},
    {SceneMode::PROFESSIONAL_PHOTO,  JsSceneMode::JS_PROFESSIONAL_PHOTO},
    {SceneMode::PROFESSIONAL_VIDEO,  JsSceneMode::JS_PROFESSIONAL_VIDEO},
    {SceneMode::HIGH_RES_PHOTO, JsSceneMode::JS_HIGH_RES_PHOTO},
    {SceneMode::SECURE, JsSceneMode::JS_SECURE_CAMERA},
    {SceneMode::QUICK_SHOT_PHOTO, JsSceneMode::JS_QUICK_SHOT_PHOTO},
    {SceneMode::APERTURE_VIDEO, JsSceneMode::JS_APERTURE_VIDEO},
    {SceneMode::PANORAMA_PHOTO, JsSceneMode::JS_PANORAMA_PHOTO},
    {SceneMode::LIGHT_PAINTING, JsSceneMode::JS_LIGHT_PAINTING},
    {SceneMode::TIMELAPSE_PHOTO, JsSceneMode::JS_TIMELAPSE_PHOTO},
    {SceneMode::FLUORESCENCE_PHOTO, JsSceneMode::JS_FLUORESCENCE_PHOTO},
};

const std::unordered_map<SceneMode, JsSceneMode> g_nativeToNapiSupportedMode_ = {
    {SceneMode::CAPTURE,  JsSceneMode::JS_CAPTURE},
    {SceneMode::VIDEO,  JsSceneMode::JS_VIDEO},
    {SceneMode::SECURE,  JsSceneMode::JS_SECURE_CAMERA},
};

CameraManagerCallbackNapi::CameraManagerCallbackNapi(napi_env env): ListenerBase(env)
{}

CameraManagerCallbackNapi::~CameraManagerCallbackNapi()
{
}

void CameraManagerCallbackNapi::OnCameraStatusCallbackAsync(const CameraStatusInfo &cameraStatusInfo) const
{
    MEDIA_DEBUG_LOG("OnCameraStatusCallbackAsync is called");
    uv_loop_s* loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (!loop) {
        MEDIA_ERR_LOG("failed to get event loop");
        return;
    }
    uv_work_t* work = new(std::nothrow) uv_work_t;
    if (!work) {
        MEDIA_ERR_LOG("failed to allocate work");
        return;
    }
    std::unique_ptr<CameraStatusCallbackInfo> callbackInfo =
        std::make_unique<CameraStatusCallbackInfo>(cameraStatusInfo, shared_from_this());
    work->data = callbackInfo.get();
    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
        CameraStatusCallbackInfo* callbackInfo = reinterpret_cast<CameraStatusCallbackInfo *>(work->data);
        if (callbackInfo) {
            auto listener = callbackInfo->listener_.lock();
            if (listener) {
                listener->OnCameraStatusCallback(callbackInfo->info_);
            }
            delete callbackInfo;
        }
        delete work;
    }, uv_qos_user_initiated);
    if (ret) {
        MEDIA_ERR_LOG("failed to execute work");
        delete work;
    } else {
        callbackInfo.release();
    }
}

void CameraManagerCallbackNapi::OnCameraStatusCallback(const CameraStatusInfo& cameraStatusInfo) const
{
    MEDIA_DEBUG_LOG("OnCameraStatusCallback is called");
    napi_value result[ARGS_TWO];
    napi_value retVal;
    napi_value propValue;
    napi_value undefinedResult;

    napi_get_undefined(env_, &result[PARAM0]);
    napi_get_undefined(env_, &result[PARAM1]);
    napi_get_undefined(env_, &undefinedResult);
    CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(cameraStatusInfo.cameraDevice, "callback cameraDevice is null");
    napi_create_object(env_, &result[PARAM1]);

    if (cameraStatusInfo.cameraDevice != nullptr) {
        napi_value cameraDeviceNapi = CameraNapiObjCameraDevice(*cameraStatusInfo.cameraDevice).GenerateNapiValue(env_);
        napi_set_named_property(env_, result[PARAM1], "camera", cameraDeviceNapi);
    } else {
        MEDIA_ERR_LOG("Camera info is null");
        napi_set_named_property(env_, result[PARAM1], "camera", undefinedResult);
    }

    int32_t jsCameraStatus = -1;
    jsCameraStatus = cameraStatusInfo.cameraStatus;
    napi_create_int64(env_, jsCameraStatus, &propValue);
    napi_set_named_property(env_, result[PARAM1], "status", propValue);
    MEDIA_INFO_LOG("CameraId: %{public}s, CameraStatus: %{public}d", cameraStatusInfo.cameraDevice->GetID().c_str(),
        cameraStatusInfo.cameraStatus);

    ExecuteCallbackNapiPara callbackNapiPara { .recv = nullptr, .argc = ARGS_TWO, .argv = result, .result = &retVal };
    ExecuteCallback("cameraStatus", callbackNapiPara);
}

void CameraManagerCallbackNapi::OnCameraStatusChanged(const CameraStatusInfo &cameraStatusInfo) const
{
    MEDIA_DEBUG_LOG("OnCameraStatusChanged is called, CameraStatus: %{public}d", cameraStatusInfo.cameraStatus);
    OnCameraStatusCallbackAsync(cameraStatusInfo);
}

void CameraManagerCallbackNapi::OnFlashlightStatusChanged(const std::string &cameraID,
    const FlashStatus flashStatus) const
{
    (void)cameraID;
    (void)flashStatus;
}

CameraMuteListenerNapi::CameraMuteListenerNapi(napi_env env): ListenerBase(env)
{
    MEDIA_DEBUG_LOG("CameraMuteListenerNapi is called.");
}

CameraMuteListenerNapi::~CameraMuteListenerNapi()
{
    MEDIA_DEBUG_LOG("~CameraMuteListenerNapi is called.");
}

void CameraMuteListenerNapi::OnCameraMuteCallbackAsync(bool muteMode) const
{
    uv_loop_s* loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (!loop) {
        MEDIA_ERR_LOG("Failed to get event loop");
        return;
    }
    uv_work_t* work = new(std::nothrow) uv_work_t;
    if (!work) {
        MEDIA_ERR_LOG("Failed to allocate work");
        return;
    }
    std::unique_ptr<CameraMuteCallbackInfo> callbackInfo =
        std::make_unique<CameraMuteCallbackInfo>(muteMode, this);
    work->data = callbackInfo.get();
    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
        CameraMuteCallbackInfo* callbackInfo = reinterpret_cast<CameraMuteCallbackInfo *>(work->data);
        if (callbackInfo) {
            callbackInfo->listener_->OnCameraMuteCallback(callbackInfo->muteMode_);
            delete callbackInfo;
        }
        delete work;
    }, uv_qos_user_initiated);
    if (ret) {
        MEDIA_ERR_LOG("Failed to execute work");
        delete work;
    } else {
        callbackInfo.release();
    }
}

void CameraMuteListenerNapi::OnCameraMuteCallback(bool muteMode) const
{
    MEDIA_DEBUG_LOG("OnCameraMuteCallback is called, muteMode: %{public}d", muteMode);
    napi_value result[ARGS_TWO];
    napi_value retVal;
    napi_get_undefined(env_, &result[PARAM0]);
    napi_get_undefined(env_, &result[PARAM1]);
    napi_get_boolean(env_, muteMode, &result[PARAM1]);

    ExecuteCallbackNapiPara callbackNapiPara { .recv = nullptr, .argc = ARGS_TWO, .argv = result, .result = &retVal };
    ExecuteCallback("cameraMute", callbackNapiPara);
}

void CameraMuteListenerNapi::OnCameraMute(bool muteMode) const
{
    MEDIA_DEBUG_LOG("OnCameraMute is called, muteMode: %{public}d", muteMode);
    OnCameraMuteCallbackAsync(muteMode);
}

TorchListenerNapi::TorchListenerNapi(napi_env env): ListenerBase(env)
{
    MEDIA_DEBUG_LOG("TorchListenerNapi is called.");
}

TorchListenerNapi::~TorchListenerNapi()
{
    MEDIA_DEBUG_LOG("~TorchListenerNapi is called.");
}

void TorchListenerNapi::OnTorchStatusChangeCallbackAsync(const TorchStatusInfo &torchStatusInfo) const
{
    MEDIA_DEBUG_LOG("OnTorchStatusChangeCallbackAsync is called");
    uv_loop_s* loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (!loop) {
        MEDIA_ERR_LOG("Failed to get event loop");
        return;
    }
    uv_work_t* work = new(std::nothrow) uv_work_t;
    if (!work) {
        MEDIA_ERR_LOG("Failed to allocate work");
        return;
    }
    std::unique_ptr<TorchStatusChangeCallbackInfo> callbackInfo =
        std::make_unique<TorchStatusChangeCallbackInfo>(torchStatusInfo, this);
    work->data = callbackInfo.get();
    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
        TorchStatusChangeCallbackInfo* callbackInfo = reinterpret_cast<TorchStatusChangeCallbackInfo *>(work->data);
        if (callbackInfo) {
            callbackInfo->listener_->OnTorchStatusChangeCallback(callbackInfo->info_);
            delete callbackInfo;
        }
        delete work;
    }, uv_qos_user_initiated);
    if (ret) {
        MEDIA_ERR_LOG("Failed to execute work");
        delete work;
    } else {
        callbackInfo.release();
    }
}

void TorchListenerNapi::OnTorchStatusChangeCallback(const TorchStatusInfo& torchStatusInfo) const
{
    MEDIA_DEBUG_LOG("OnTorchStatusChangeCallback is called");
    napi_handle_scope scope = nullptr;
    napi_open_handle_scope(env_, &scope);
    if (scope == nullptr) {
        return;
    }
    napi_value result[ARGS_TWO];
    napi_value retVal;
    napi_value propValue;

    napi_get_undefined(env_, &result[PARAM0]);
    napi_get_undefined(env_, &result[PARAM1]);

    napi_create_object(env_, &result[PARAM1]);

    napi_get_boolean(env_, torchStatusInfo.isTorchAvailable, &propValue);
    napi_set_named_property(env_, result[PARAM1], "isTorchAvailable", propValue);
    napi_get_boolean(env_, torchStatusInfo.isTorchActive, &propValue);
    napi_set_named_property(env_, result[PARAM1], "isTorchActive", propValue);
    napi_create_double(env_, torchStatusInfo.torchLevel, &propValue);
    napi_set_named_property(env_, result[PARAM1], "torchLevel", propValue);

    ExecuteCallbackNapiPara callbackNapiPara { .recv = nullptr, .argc = ARGS_TWO, .argv = result, .result = &retVal };
    ExecuteCallback("torchStatusChange", callbackNapiPara);
    napi_close_handle_scope(env_, scope);
}

void TorchListenerNapi::OnTorchStatusChange(const TorchStatusInfo &torchStatusInfo) const
{
    MEDIA_DEBUG_LOG("OnTorchStatusChange is called");
    OnTorchStatusChangeCallbackAsync(torchStatusInfo);
}

FoldListenerNapi::FoldListenerNapi(napi_env env): ListenerBase(env)
{
    MEDIA_DEBUG_LOG("FoldListenerNapi is called.");
}

FoldListenerNapi::~FoldListenerNapi()
{
    MEDIA_DEBUG_LOG("~FoldListenerNapi is called.");
}

void FoldListenerNapi::OnFoldStatusChangedCallbackAsync(const FoldStatusInfo &foldStatusInfo) const
{
    MEDIA_DEBUG_LOG("OnFoldStatusChangedCallbackAsync is called");
    uv_loop_s* loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (!loop) {
        MEDIA_ERR_LOG("Failed to get event loop");
        return;
    }
    uv_work_t* work = new(std::nothrow) uv_work_t;
    if (!work) {
        MEDIA_ERR_LOG("Failed to allocate work");
        return;
    }
    std::unique_ptr<FoldStatusChangeCallbackInfo> callbackInfo =
        std::make_unique<FoldStatusChangeCallbackInfo>(foldStatusInfo, this);
    work->data = callbackInfo.get();
    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
        FoldStatusChangeCallbackInfo* callbackInfo = reinterpret_cast<FoldStatusChangeCallbackInfo *>(work->data);
        if (callbackInfo) {
            callbackInfo->listener_->OnFoldStatusChangedCallback(callbackInfo->info_);
            delete callbackInfo;
        }
        delete work;
    }, uv_qos_user_initiated);
    if (ret) {
        MEDIA_ERR_LOG("Failed to execute work");
        delete work;
    } else {
        callbackInfo.release();
    }
}

void FoldListenerNapi::OnFoldStatusChangedCallback(const FoldStatusInfo& foldStatusInfo) const
{
    MEDIA_DEBUG_LOG("OnFoldStatusChangedCallback is called");
    napi_handle_scope scope = nullptr;
    napi_open_handle_scope(env_, &scope);
    if (scope == nullptr) {
        MEDIA_ERR_LOG("scope is null");
        return;
    }
    napi_value result[ARGS_TWO];
    napi_value retVal = nullptr;
    napi_value propValue = nullptr;
    napi_value errCode;

    napi_create_object(env_, &result[PARAM0]);
    napi_create_object(env_, &result[PARAM1]);
    napi_create_int32(env_, foldStatusInfo.foldStatus, &propValue);
    napi_set_named_property(env_, result[PARAM1], "foldStatus", propValue);
    if (napi_create_array(env_, &propValue) != napi_ok) {
        MEDIA_ERR_LOG("Failed to create array napi wrapper object");
        return;
    }
    auto supportedCameras = foldStatusInfo.supportedCameras;
    if (!supportedCameras.empty()) {
        napi_create_int32(env_, 0, &errCode);
        napi_set_named_property(env_, result[PARAM0], "code", errCode);
        for (size_t i = 0; i < supportedCameras.size(); i++) {
            if (supportedCameras[i] == nullptr) {
                MEDIA_ERR_LOG("cameraDevice is null");
                continue;
            }
            napi_value camera = CameraNapiObjCameraDevice(*supportedCameras[i]).GenerateNapiValue(env_);
            if (napi_set_element(env_, propValue, i, camera) != napi_ok) {
                MEDIA_ERR_LOG("Failed to create profile napi wrapper object");
                return;
            }
        }
    } else {
        MEDIA_ERR_LOG("supportedCameras is empty");
        napi_create_int32(env_, CameraErrorCode::SERVICE_FATL_ERROR, &errCode);
        napi_set_named_property(env_, result[PARAM0], "code", errCode);
    }
    napi_set_named_property(env_, result[PARAM1], "supportedCameras", propValue);
    ExecuteCallbackNapiPara callbackNapiPara { .recv = nullptr, .argc = ARGS_TWO, .argv = result, .result = &retVal };
    ExecuteCallback("foldStatusChange", callbackNapiPara);
    napi_close_handle_scope(env_, scope);
}

void FoldListenerNapi::OnFoldStatusChanged(const FoldStatusInfo &foldStatusInfo) const
{
    MEDIA_DEBUG_LOG("OnFoldStatusChanged is called");
    OnFoldStatusChangedCallbackAsync(foldStatusInfo);
}

const std::unordered_map<JsSceneMode, SceneMode> g_jsToFwMode_ = {
    {JsSceneMode::JS_NORMAL, SceneMode::NORMAL},
    {JsSceneMode::JS_CAPTURE, SceneMode::CAPTURE},
    {JsSceneMode::JS_VIDEO, SceneMode::VIDEO},
    {JsSceneMode::JS_SECURE_CAMERA, SceneMode::SECURE},
};

const std::unordered_map<JsSceneMode, SceneMode> g_jsToFwMode4Sys_ = {
    {JsSceneMode::JS_NORMAL, SceneMode::NORMAL},
    {JsSceneMode::JS_CAPTURE, SceneMode::CAPTURE},
    {JsSceneMode::JS_VIDEO, SceneMode::VIDEO},
    {JsSceneMode::JS_PORTRAIT, SceneMode::PORTRAIT},
    {JsSceneMode::JS_NIGHT, SceneMode::NIGHT},
    {JsSceneMode::JS_SLOW_MOTION, SceneMode::SLOW_MOTION},
    {JsSceneMode::JS_CAPTURE_MARCO, SceneMode::CAPTURE_MACRO},
    {JsSceneMode::JS_VIDEO_MARCO, SceneMode::VIDEO_MACRO},
    {JsSceneMode::JS_PROFESSIONAL_PHOTO, SceneMode::PROFESSIONAL_PHOTO},
    {JsSceneMode::JS_PROFESSIONAL_VIDEO, SceneMode::PROFESSIONAL_VIDEO},
    {JsSceneMode::JS_HIGH_RES_PHOTO, SceneMode::HIGH_RES_PHOTO},
    {JsSceneMode::JS_SECURE_CAMERA, SceneMode::SECURE},
    {JsSceneMode::JS_QUICK_SHOT_PHOTO, SceneMode::QUICK_SHOT_PHOTO},
    {JsSceneMode::JS_APERTURE_VIDEO, SceneMode::APERTURE_VIDEO},
    {JsSceneMode::JS_PANORAMA_PHOTO, SceneMode::PANORAMA_PHOTO},
    {JsSceneMode::JS_LIGHT_PAINTING, SceneMode::LIGHT_PAINTING},
    {JsSceneMode::JS_TIMELAPSE_PHOTO, SceneMode::TIMELAPSE_PHOTO},
    {JsSceneMode::JS_FLUORESCENCE_PHOTO, SceneMode::FLUORESCENCE_PHOTO},
};

static std::unordered_map<JsPolicyType, PolicyType> g_jsToFwPolicyType_ = {
    {JsPolicyType::JS_PRIVACY, PolicyType::PRIVACY},
};

std::unordered_map<int32_t, std::function<napi_value(napi_env)>> g_sessionFactories4Sys_ = {
    {JsSceneMode::JS_CAPTURE, [] (napi_env env) {
        return PhotoSessionForSysNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_VIDEO, [] (napi_env env) {
        return VideoSessionForSysNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_PORTRAIT, [] (napi_env env) { return PortraitSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_NIGHT, [] (napi_env env) { return NightSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_SLOW_MOTION, [] (napi_env env) { return SlowMotionSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_PROFESSIONAL_PHOTO, [] (napi_env env) {
        return ProfessionSessionNapi::CreateCameraSession(env, SceneMode::PROFESSIONAL_PHOTO); }},
    {JsSceneMode::JS_PROFESSIONAL_VIDEO, [] (napi_env env) {
        return ProfessionSessionNapi::CreateCameraSession(env, SceneMode::PROFESSIONAL_VIDEO); }},
    {JsSceneMode::JS_CAPTURE_MARCO, [] (napi_env env) {
        return MacroPhotoSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_VIDEO_MARCO, [] (napi_env env) {
        return MacroVideoSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_HIGH_RES_PHOTO, [] (napi_env env) {
        return HighResPhotoSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_SECURE_CAMERA, [] (napi_env env) {
        return SecureCameraSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_QUICK_SHOT_PHOTO, [] (napi_env env) {
        return QuickShotPhotoSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_APERTURE_VIDEO, [] (napi_env env) {
        return ApertureVideoSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_PANORAMA_PHOTO, [] (napi_env env) {
        return PanoramaSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_LIGHT_PAINTING, [] (napi_env env) {
        return LightPaintingSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_TIMELAPSE_PHOTO, [] (napi_env env) {
        return TimeLapsePhotoSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_FLUORESCENCE_PHOTO, [] (napi_env env) {
        return FluorescencePhotoSessionNapi::CreateCameraSession(env); }},
};

std::unordered_map<int32_t, std::function<napi_value(napi_env)>> g_sessionFactories = {
    {JsSceneMode::JS_CAPTURE, [] (napi_env env) {
        return PhotoSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_VIDEO, [] (napi_env env) {
        return VideoSessionNapi::CreateCameraSession(env); }},
    {JsSceneMode::JS_SECURE_CAMERA, [] (napi_env env) {
        return SecureCameraSessionNapi::CreateCameraSession(env); }},
};

CameraManagerNapi::CameraManagerNapi() : env_(nullptr)
{
    CAMERA_SYNC_TRACE;
}

CameraManagerNapi::~CameraManagerNapi()
{
    MEDIA_DEBUG_LOG("~CameraManagerNapi is called");
}

// Constructor callback
napi_value CameraManagerNapi::CameraManagerNapiConstructor(napi_env env, napi_callback_info info)
{
    MEDIA_DEBUG_LOG("CameraManagerNapiConstructor is called");
    napi_status status;
    napi_value result = nullptr;
    napi_value thisVar = nullptr;

    napi_get_undefined(env, &result);
    CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);

    if (status == napi_ok && thisVar != nullptr) {
        std::unique_ptr<CameraManagerNapi> obj = std::make_unique<CameraManagerNapi>();
        obj->env_ = env;
        obj->cameraManager_ = CameraManager::GetInstance();
        if (obj->cameraManager_ == nullptr) {
            MEDIA_ERR_LOG("Failure wrapping js to native napi, obj->cameraManager_ null");
            return result;
        }
        status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
                           CameraManagerNapi::CameraManagerNapiDestructor, nullptr, nullptr);
        if (status == napi_ok) {
            obj.release();
            return thisVar;
        } else {
            MEDIA_ERR_LOG("Failure wrapping js to native napi");
        }
    }
    MEDIA_ERR_LOG("CameraManagerNapiConstructor call Failed!");
    return result;
}

void CameraManagerNapi::CameraManagerNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
{
    MEDIA_DEBUG_LOG("CameraManagerNapiDestructor is called");
    CameraManagerNapi* camera = reinterpret_cast<CameraManagerNapi*>(nativeObject);
    if (camera != nullptr) {
        delete camera;
    }
}

napi_value CameraManagerNapi::Init(napi_env env, napi_value exports)
{
    MEDIA_DEBUG_LOG("Init is called");
    napi_status status;
    napi_value ctorObj;
    int32_t refCount = 1;

    napi_property_descriptor camera_mgr_properties[] = {
        // CameraManager
        DECLARE_NAPI_FUNCTION("getSupportedCameras", GetSupportedCameras),
        DECLARE_NAPI_FUNCTION("getSupportedSceneModes", GetSupportedModes),
        DECLARE_NAPI_FUNCTION("getSupportedOutputCapability", GetSupportedOutputCapability),
        DECLARE_NAPI_FUNCTION("isCameraMuted", IsCameraMuted),
        DECLARE_NAPI_FUNCTION("isCameraMuteSupported", IsCameraMuteSupported),
        DECLARE_NAPI_FUNCTION("muteCamera", MuteCamera),
        DECLARE_NAPI_FUNCTION("muteCameraPersistent", MuteCameraPersist),
        DECLARE_NAPI_FUNCTION("prelaunch", PrelaunchCamera),
        DECLARE_NAPI_FUNCTION("preSwitchCamera", PreSwitchCamera),
        DECLARE_NAPI_FUNCTION("isPrelaunchSupported", IsPrelaunchSupported),
        DECLARE_NAPI_FUNCTION("setPrelaunchConfig", SetPrelaunchConfig),
        DECLARE_NAPI_FUNCTION("createCameraInput", CreateCameraInputInstance),
        DECLARE_NAPI_FUNCTION("createCaptureSession", CreateCameraSessionInstance),
        DECLARE_NAPI_FUNCTION("createSession", CreateSessionInstance),
        DECLARE_NAPI_FUNCTION("createPreviewOutput", CreatePreviewOutputInstance),
        DECLARE_NAPI_FUNCTION("createDeferredPreviewOutput", CreateDeferredPreviewOutputInstance),
        DECLARE_NAPI_FUNCTION("createPhotoOutput", CreatePhotoOutputInstance),
        DECLARE_NAPI_FUNCTION("createVideoOutput", CreateVideoOutputInstance),
        DECLARE_NAPI_FUNCTION("createMetadataOutput", CreateMetadataOutputInstance),
        DECLARE_NAPI_FUNCTION("createDepthDataOutput", CreateDepthDataOutputInstance),
        DECLARE_NAPI_FUNCTION("isTorchSupported", IsTorchSupported),
        DECLARE_NAPI_FUNCTION("isTorchModeSupported", IsTorchModeSupported),
        DECLARE_NAPI_FUNCTION("getTorchMode", GetTorchMode),
        DECLARE_NAPI_FUNCTION("setTorchMode", SetTorchMode),
        DECLARE_NAPI_FUNCTION("on", On),
        DECLARE_NAPI_FUNCTION("once", Once),
        DECLARE_NAPI_FUNCTION("off", Off)
    };

    status = napi_define_class(env, CAMERA_MANAGER_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
                               CameraManagerNapiConstructor, nullptr,
                               sizeof(camera_mgr_properties) / sizeof(camera_mgr_properties[PARAM0]),
                               camera_mgr_properties, &ctorObj);
    if (status == napi_ok) {
        if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
            status = napi_set_named_property(env, exports, CAMERA_MANAGER_NAPI_CLASS_NAME, ctorObj);
            if (status == napi_ok) {
                return exports;
            }
        }
    }
    MEDIA_ERR_LOG("Init call Failed!");
    return nullptr;
}

napi_value CameraManagerNapi::CreateCameraManager(napi_env env)
{
    MEDIA_INFO_LOG("CreateCameraManager is called");
    napi_status status;
    napi_value result = nullptr;
    napi_value ctor;

    status = napi_get_reference_value(env, sConstructor_, &ctor);
    if (status == napi_ok) {
        status = napi_new_instance(env, ctor, 0, nullptr, &result);
        if (status == napi_ok) {
            return result;
        } else {
            MEDIA_ERR_LOG("New instance could not be obtained");
        }
    }
    napi_get_undefined(env, &result);
    MEDIA_ERR_LOG("CreateCameraManager call Failed!");
    return result;
}

static napi_value CreateCameraJSArray(napi_env env, std::vector<sptr<CameraDevice>> cameraObjList)
{
    MEDIA_DEBUG_LOG("CreateCameraJSArray is called");
    napi_value cameraArray = nullptr;

    if (cameraObjList.empty()) {
        MEDIA_ERR_LOG("cameraObjList is empty");
    }

    napi_status status = napi_create_array(env, &cameraArray);
    if (status == napi_ok) {
        for (size_t i = 0; i < cameraObjList.size(); i++) {
            if (cameraObjList[i] == nullptr) {
                continue;
            }
            napi_value camera = CameraNapiObjCameraDevice(*cameraObjList[i]).GenerateNapiValue(env);
            if (camera == nullptr || napi_set_element(env, cameraArray, i, camera) != napi_ok) {
                MEDIA_ERR_LOG("Failed to create camera napi wrapper object");
                return nullptr;
            }
        }
    }
    return cameraArray;
}

napi_value CameraManagerNapi::CreateCameraSessionInstance(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("CreateCameraSessionInstance is called");
    napi_status status;
    napi_value result = nullptr;
    size_t argc = ARGS_ZERO;
    napi_value argv[ARGS_ZERO];
    napi_value thisVar = nullptr;

    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);

    napi_get_undefined(env, &result);

    CameraManagerNapi* cameraManagerNapi = nullptr;
    status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&cameraManagerNapi));
    if (status != napi_ok || cameraManagerNapi == nullptr) {
        MEDIA_ERR_LOG("napi_unwrap failure!");
        return nullptr;
    }
    result = CameraSessionNapi::CreateCameraSession(env);
    return result;
}

napi_value CameraManagerNapi::CreateSessionInstance(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("CreateSessionInstance is called");
    CameraManagerNapi* cameraManagerNapi = nullptr;
    int32_t jsModeName = -1;
    CameraNapiParamParser jsParamParser(env, info, cameraManagerNapi, jsModeName);
    if (!jsParamParser.AssertStatus(INVALID_ARGUMENT, "Create session invalid argument!")) {
        MEDIA_ERR_LOG("CameraManagerNapi::CreateSessionInstance invalid argument: %{public}d", jsModeName);
    }
    MEDIA_INFO_LOG("CameraManagerNapi::CreateSessionInstance mode = %{public}d", jsModeName);
    napi_value result = nullptr;
    std::unordered_map<int32_t, std::function<napi_value(napi_env)>> sessionFactories = g_sessionFactories;
    if (CameraNapiSecurity::CheckSystemApp(env, false)) {
        sessionFactories = g_sessionFactories4Sys_;
    }
    if (sessionFactories.find(jsModeName) != sessionFactories.end()) {
        result = sessionFactories[jsModeName](env);
    } else {
        MEDIA_ERR_LOG("CameraManagerNapi::CreateSessionInstance mode = %{public}d not supported", jsModeName);
        CameraNapiUtils::ThrowError(env, INVALID_ARGUMENT, "Invalid js mode");
    }
    return result;
}

bool ParsePrelaunchConfig(napi_env env, napi_value root, PrelaunchConfig* prelaunchConfig)
{
    napi_value res = nullptr;
    int32_t intValue;
    std::string cameraId {};
    CameraNapiObject cameraInfoObj { { { "cameraId", &cameraId } } };
    CameraNapiObject cameraDeviceObj { { { "cameraDevice", &cameraInfoObj } } };
    CameraNapiParamParser paramParser { env, { root }, cameraDeviceObj };
    if (!paramParser.AssertStatus(INVALID_ARGUMENT, "camera info is invalid.")) {
        MEDIA_ERR_LOG("ParsePrelaunchConfig get camera device failure!");
        return false;
    }
    prelaunchConfig->cameraDevice_ = CameraManager::GetInstance()->GetCameraDeviceFromId(cameraId);
    if (prelaunchConfig->cameraDevice_ == nullptr) {
        MEDIA_ERR_LOG("ParsePrelaunchConfig get camera device failure! cameraId:%{public}s", cameraId.c_str());
    }
    if (napi_get_named_property(env, root, "restoreParamType", &res) == napi_ok) {
        napi_get_value_int32(env, res, &intValue);
        prelaunchConfig->restoreParamType = static_cast<RestoreParamType>(intValue);
        MEDIA_INFO_LOG("SetPrelaunchConfig restoreParamType = %{public}d", intValue);
    }

    if (napi_get_named_property(env, root, "activeTime", &res) == napi_ok) {
        napi_get_value_int32(env, res, &intValue);
        prelaunchConfig->activeTime = intValue;
        MEDIA_INFO_LOG("SetPrelaunchConfig activeTime = %{public}d", intValue);
    }
    return true;
}

bool ParseSettingParam(napi_env env, napi_value root, EffectParam* effectParam)
{
    napi_value res = nullptr;
    if (napi_get_named_property(env, root, "settingParam",  &res) == napi_ok) {
        napi_value tempValue = nullptr;
        int32_t effectValue;
        if (napi_get_named_property(env, res, "skinSmoothLevel", &tempValue) == napi_ok) {
            napi_get_value_int32(env, tempValue, &effectValue);
            effectParam->skinSmoothLevel = effectValue;
        }
        if (napi_get_named_property(env, res, "faceSlender", &tempValue) == napi_ok) {
            napi_get_value_int32(env, tempValue, &effectValue);
            effectParam->faceSlender = effectValue;
        }

        if (napi_get_named_property(env, res, "skinTone", &tempValue) == napi_ok) {
            napi_get_value_int32(env, tempValue, &effectValue);
            effectParam->skinTone = effectValue;
        }
        MEDIA_INFO_LOG("SetPrelaunchConfig effectParam = %{public}d", effectParam->skinSmoothLevel);
    }
    return true;
}

napi_value CameraManagerNapi::CreatePreviewOutputInstance(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("CreatePreviewOutputInstance is called");
    std::string surfaceId;
    CameraManagerNapi* cameraManagerNapi = nullptr;
    size_t napiArgsSize = CameraNapiUtils::GetNapiArgs(env, info);
    MEDIA_INFO_LOG("CameraManagerNapi::CreatePreviewOutputInstance napi args size is %{public}zu", napiArgsSize);

    // Check two parameters
    if (napiArgsSize == 2) { // 2 parameters condition
        Profile profile;
        CameraNapiObject profileSizeObj {{
            { "width", &profile.size_.width },
            { "height", &profile.size_.height }
        }};
        CameraNapiObject profileNapiOjbect {{
            { "size", &profileSizeObj },
            { "format", reinterpret_cast<int32_t*>(&profile.format_) }
        }};
        CameraNapiParamParser jsParamParser(env, info, cameraManagerNapi, profileNapiOjbect, surfaceId);
        if (!jsParamParser.AssertStatus(
            INVALID_ARGUMENT, "CameraManagerNapi::CreatePreviewOutputInstance 2 args parse error")) {
            return nullptr;
        }
        MEDIA_INFO_LOG("CameraManagerNapi::CreatePreviewOutputInstance ParseProfile "
                       "size.width = %{public}d, size.height = %{public}d, format = %{public}d, surfaceId = %{public}s",
            profile.size_.width, profile.size_.height, profile.format_, surfaceId.c_str());
        return PreviewOutputNapi::CreatePreviewOutput(env, profile, surfaceId);
    }

    // Check one parameters
    CameraNapiParamParser jsParamParser = CameraNapiParamParser(env, info, cameraManagerNapi, surfaceId);
    if (!jsParamParser.AssertStatus(
        INVALID_ARGUMENT, "CameraManagerNapi::CreatePreviewOutputInstance 1 args parse error")) {
        return nullptr;
    }
    MEDIA_INFO_LOG("CameraManagerNapi::CreatePreviewOutputInstance surfaceId : %{public}s", surfaceId.c_str());
    return PreviewOutputNapi::CreatePreviewOutput(env, surfaceId);
}

napi_value CameraManagerNapi::CreateDeferredPreviewOutputInstance(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("CreateDeferredPreviewOutputInstance is called");
    if (!CameraNapiSecurity::CheckSystemApp(env)) {
        MEDIA_ERR_LOG("SystemApi CreateDeferredPreviewOutputInstance is called!");
        return nullptr;
    }

    CameraManagerNapi* cameraManagerNapi = nullptr;
    Profile profile;
    CameraNapiObject profileSizeObj {{
        { "width", &profile.size_.width },
        { "height", &profile.size_.height }
    }};
    CameraNapiObject profileNapiOjbect {{
        { "size", &profileSizeObj },
        { "format", reinterpret_cast<int32_t*>(&profile.format_) }
    }};

    CameraNapiParamParser jsParamParser(env, info, cameraManagerNapi, profileNapiOjbect);
    if (!jsParamParser.AssertStatus(
        INVALID_ARGUMENT, "CameraManagerNapi::CreateDeferredPreviewOutput args parse error")) {
        return nullptr;
    }
    MEDIA_INFO_LOG("CameraManagerNapi::CreateDeferredPreviewOutput ParseProfile "
                   "size.width = %{public}d, size.height = %{public}d, format = %{public}d",
        profile.size_.width, profile.size_.height, profile.format_);
    return PreviewOutputNapi::CreateDeferredPreviewOutput(env, profile);
}

napi_value CameraManagerNapi::CreatePhotoOutputInstance(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("CreatePhotoOutputInstance is called");
    std::string surfaceId;
    CameraManagerNapi* cameraManagerNapi = nullptr;
    size_t napiArgsSize = CameraNapiUtils::GetNapiArgs(env, info);
    MEDIA_INFO_LOG("CameraManagerNapi::CreatePhotoOutputInstance napi args size is %{public}zu", napiArgsSize);

    Profile profile;
    CameraNapiObject profileSizeObj {{
        { "width", &profile.size_.width },
        { "height", &profile.size_.height }
    }};
    CameraNapiObject profileNapiOjbect {{
        { "size", &profileSizeObj },
        { "format", reinterpret_cast<int32_t*>(&profile.format_) }
    }};

    if (napiArgsSize == 2) { // 2 parameters condition
        if (!CameraNapiParamParser(env, info, cameraManagerNapi, profileNapiOjbect, surfaceId)
                 .AssertStatus(INVALID_ARGUMENT, "CameraManagerNapi::CreatePhotoOutputInstance 2 args parse error")) {
            return nullptr;
        }
        MEDIA_INFO_LOG("CameraManagerNapi::CreatePhotoOutputInstance ParseProfile "
                       "size.width = %{public}d, size.height = %{public}d, format = %{public}d, surfaceId = %{public}s",
            profile.size_.width, profile.size_.height, profile.format_, surfaceId.c_str());
        return PhotoOutputNapi::CreatePhotoOutput(env, profile, surfaceId);
    } else if (napiArgsSize == 1) { // 1 parameters condition
        // Check one parameter only profile
        if (CameraNapiParamParser(env, info, cameraManagerNapi, profileNapiOjbect).IsStatusOk()) {
            MEDIA_INFO_LOG(
                "CameraManagerNapi::CreatePhotoOutputInstance ParseProfile "
                "size.width = %{public}d, size.height = %{public}d, format = %{public}d, surfaceId = %{public}s",
                profile.size_.width, profile.size_.height, profile.format_, surfaceId.c_str());
            return PhotoOutputNapi::CreatePhotoOutput(env, profile, "");
        }

        // Check one parameter only surfaceId
        if (!CameraNapiParamParser(env, info, cameraManagerNapi, surfaceId)
                 .AssertStatus(INVALID_ARGUMENT, "CameraManagerNapi::CreatePhotoOutputInstance 1 args parse error")) {
            return nullptr;
        }
        MEDIA_INFO_LOG("CameraManagerNapi::CreatePhotoOutputInstance surfaceId : %{public}s", surfaceId.c_str());
        return PhotoOutputNapi::CreatePhotoOutput(env, surfaceId);
    }

    MEDIA_WARNING_LOG("CameraManagerNapi::CreatePhotoOutputInstance with none parameter");
    // Check none parameter
    if (!CameraNapiParamParser(env, info, cameraManagerNapi)
             .AssertStatus(INVALID_ARGUMENT, "CameraManagerNapi::CreatePhotoOutputInstance args parse error")) {
        return nullptr;
    }
    return PhotoOutputNapi::CreatePhotoOutput(env, "");
}

napi_value CameraManagerNapi::CreateVideoOutputInstance(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("CreateVideoOutputInstance is called");
    std::string surfaceId;
    CameraManagerNapi* cameraManagerNapi = nullptr;
    size_t napiArgsSize = CameraNapiUtils::GetNapiArgs(env, info);
    MEDIA_INFO_LOG("CameraManagerNapi::CreateVideoOutputInstance napi args size is %{public}zu", napiArgsSize);

    if (napiArgsSize == 2) { // 2 parameters condition
        VideoProfile videoProfile;
        videoProfile.framerates_.resize(2); // framerate size is 2
        CameraNapiObject profileSizeObj {{
            { "width", &videoProfile.size_.width },
            { "height", &videoProfile.size_.height }
        }};
        CameraNapiObject profileFrameRateObj {{
            { "min", &videoProfile.framerates_[0] },
            { "max", &videoProfile.framerates_[1] }
        }};
        CameraNapiObject profileNapiOjbect {{
            { "size", &profileSizeObj },
            { "frameRateRange", &profileFrameRateObj },
            { "format", reinterpret_cast<int32_t*>(&videoProfile.format_) }
        }};

        if (!CameraNapiParamParser(env, info, cameraManagerNapi, profileNapiOjbect, surfaceId)
                 .AssertStatus(INVALID_ARGUMENT, "CameraManagerNapi::CreateVideoOutputInstance 2 args parse error")) {
            return nullptr;
        }
        MEDIA_INFO_LOG(
            "CameraManagerNapi::CreateVideoOutputInstance ParseVideoProfile "
            "size.width = %{public}d, size.height = %{public}d, format = %{public}d, frameRateMin = %{public}d, "
            "frameRateMax = %{public}d, surfaceId = %{public}s",
            videoProfile.size_.width, videoProfile.size_.height, videoProfile.format_, videoProfile.framerates_[0],
            videoProfile.framerates_[1], surfaceId.c_str());
        return VideoOutputNapi::CreateVideoOutput(env, videoProfile, surfaceId);
    }

    MEDIA_WARNING_LOG("CameraManagerNapi::CreateVideoOutputInstance with only surfaceId");
    // Check one parameters only surfaceId
    if (!CameraNapiParamParser(env, info, cameraManagerNapi, surfaceId)
             .AssertStatus(INVALID_ARGUMENT, "CameraManagerNapi::CreateVideoOutputInstance args parse error")) {
        return nullptr;
    }
    MEDIA_INFO_LOG("CameraManagerNapi::CreateVideoOutputInstance surfaceId : %{public}s", surfaceId.c_str());
    return VideoOutputNapi::CreateVideoOutput(env, surfaceId);
}

napi_value CameraManagerNapi::CreateDepthDataOutputInstance(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("CreateDepthDataOutputInstance is called");
    CameraManagerNapi* cameraManagerNapi = nullptr;
    size_t napiArgsSize = CameraNapiUtils::GetNapiArgs(env, info);
    MEDIA_INFO_LOG("CameraManagerNapi::CreateDepthDataOutputInstance napi args size is %{public}zu", napiArgsSize);

    DepthProfile depthProfile;
    CameraNapiObject profileSizeObj {{
        { "width", &depthProfile.size_.width },
        { "height", &depthProfile.size_.height }
    }};
    CameraNapiObject profileNapiOjbect {{
        { "size", &profileSizeObj },
        { "dataAccuracy", reinterpret_cast<int32_t*>(&depthProfile.dataAccuracy_) },
        { "format", reinterpret_cast<int32_t*>(&depthProfile.format_) }
    }};

    if (!CameraNapiParamParser(env, info, cameraManagerNapi, profileNapiOjbect)
            .AssertStatus(INVALID_ARGUMENT, "CameraManagerNapi::CreateDepthDataOutputInstance 1 args parse error")) {
        return nullptr;
    }
    MEDIA_INFO_LOG(
        "CameraManagerNapi::CreateDepthDataOutputInstance ParseDepthProfile "
        "size.width = %{public}d, size.height = %{public}d, format = %{public}d, dataAccuracy = %{public}d,",
        depthProfile.size_.width, depthProfile.size_.height, depthProfile.format_, depthProfile.dataAccuracy_);
    return DepthDataOutputNapi::CreateDepthDataOutput(env, depthProfile);
}

napi_value CameraManagerNapi::CreateMetadataOutputInstance(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("CreateMetadataOutputInstance is called");
    napi_status status;
    napi_value result = nullptr;
    size_t argc = ARGS_ONE;
    napi_value argv[ARGS_ONE] = {0};
    napi_value thisVar = nullptr;

    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
    if (!CameraNapiUtils::CheckInvalidArgument(env, argc, ARGS_ONE, argv, CREATE_METADATA_OUTPUT_INSTANCE)) {
        return result;
    }

    napi_get_undefined(env, &result);
    CameraManagerNapi* cameraManagerNapi = nullptr;
    status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&cameraManagerNapi));
    if (status != napi_ok || cameraManagerNapi == nullptr) {
        MEDIA_ERR_LOG("napi_unwrap failure!");
        return nullptr;
    }
    std::vector<MetadataObjectType> metadataObjectTypes;
    CameraNapiUtils::ParseMetadataObjectTypes(env, argv[PARAM0], metadataObjectTypes);
    result = MetadataOutputNapi::CreateMetadataOutput(env, metadataObjectTypes);
    return result;
}

napi_value CameraManagerNapi::GetSupportedCameras(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("GetSupportedCameras is called");
    CameraManagerNapi* cameraManagerNapi;
    CameraNapiParamParser paramParser(env, info, cameraManagerNapi);
    if (!paramParser.AssertStatus(INVALID_ARGUMENT, "invalid argument.")) {
        MEDIA_ERR_LOG("CameraManagerNapi::GetSupportedCameras invalid argument");
        return nullptr;
    }
    std::vector<sptr<CameraDevice>> cameraObjList = cameraManagerNapi->cameraManager_->GetSupportedCameras();
    napi_value result = GetCachedSupportedCameras(env, cameraObjList);
    if (result == nullptr) {
        result = CreateCameraJSArray(env, cameraObjList);
        CacheSupportedCameras(env, cameraObjList, result);
    }
    MEDIA_DEBUG_LOG("CameraManagerNapi::GetSupportedCameras size=[%{public}zu]", cameraObjList.size());
    return result;
}

static napi_value CreateSceneModeJSArray(napi_env env, std::vector<SceneMode> nativeArray)
{
    MEDIA_DEBUG_LOG("CreateSceneModeJSArray is called");
    napi_value jsArray = nullptr;
    napi_value item = nullptr;

    if (nativeArray.empty()) {
        MEDIA_ERR_LOG("nativeArray is empty");
    }

    napi_status status = napi_create_array(env, &jsArray);
    std::unordered_map<SceneMode, JsSceneMode> nativeToNapiMap = g_nativeToNapiSupportedMode_;
    if (CameraNapiSecurity::CheckSystemApp(env, false)) {
        nativeToNapiMap = g_nativeToNapiSupportedModeForSystem_;
    }
    if (status == napi_ok) {
        uint8_t index = 0;
        for (size_t i = 0; i < nativeArray.size(); i++) {
            auto itr = nativeToNapiMap.find(nativeArray[i]);
            if (itr != nativeToNapiMap.end()) {
                napi_create_int32(env, itr->second, &item);
                napi_set_element(env, jsArray, index, item);
                index++;
            }
        }
    }
    return jsArray;
}

napi_value CameraManagerNapi::GetSupportedModes(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("GetSupportedModes is called");
    CameraManagerNapi* cameraManagerNapi = nullptr;
    std::string cameraId {};
    CameraNapiObject cameraInfoObj { { { "cameraId", &cameraId } } };
    if (!CameraNapiParamParser(env, info, cameraManagerNapi, cameraInfoObj)
             .AssertStatus(INVALID_ARGUMENT, "GetSupportedModes args parse error")) {
        return nullptr;
    }
    sptr<CameraDevice> cameraInfo = cameraManagerNapi->cameraManager_->GetCameraDeviceFromId(cameraId);
    if (cameraInfo == nullptr) {
        MEDIA_ERR_LOG("CameraManagerNapi::GetSupportedModes get camera info fail");
        CameraNapiUtils::ThrowError(env, INVALID_ARGUMENT, "Get camera info fail");
        return nullptr;
    }

    std::vector<SceneMode> modeObjList = cameraManagerNapi->cameraManager_->GetSupportedModes(cameraInfo);
    for (auto it = modeObjList.begin(); it != modeObjList.end(); it++) {
        if (*it == SCAN) {
            modeObjList.erase(it);
            break;
        }
    }
    if (modeObjList.empty()) {
        modeObjList.emplace_back(CAPTURE);
        modeObjList.emplace_back(VIDEO);
    }
    MEDIA_INFO_LOG("CameraManagerNapi::GetSupportedModes size=[%{public}zu]", modeObjList.size());
    return CreateSceneModeJSArray(env, modeObjList);
}

void CameraManagerNapi::GetSupportedOutputCapabilityAdaptNormalMode(
    SceneMode fwkMode, sptr<CameraDevice>& cameraInfo, sptr<CameraOutputCapability>& outputCapability)
{
    if (fwkMode == SceneMode::NORMAL && cameraInfo->GetPosition() == CAMERA_POSITION_FRONT) {
        auto defaultVideoProfiles = cameraInfo->modeVideoProfiles_[SceneMode::NORMAL];
        if (!defaultVideoProfiles.empty()) {
            MEDIA_INFO_LOG("return align videoProfile size = %{public}zu", defaultVideoProfiles.size());
            outputCapability->SetVideoProfiles(defaultVideoProfiles);
        }
    }
}

sptr<CameraDevice> CameraManagerNapi::GetSupportedOutputCapabilityGetCameraInfo(
    napi_env env, napi_callback_info info, CameraManagerNapi*& cameraManagerNapi, int32_t& jsSceneMode)
{
    std::string cameraId {};
    CameraNapiObject cameraInfoObj { { { "cameraId", &cameraId } } };
    size_t napiArgsSize = CameraNapiUtils::GetNapiArgs(env, info);
    MEDIA_INFO_LOG("CameraManagerNapi::GetSupportedOutputCapability napi args size is %{public}zu", napiArgsSize);
    if (napiArgsSize == ARGS_ONE) {
        if (!CameraNapiParamParser(env, info, cameraManagerNapi, cameraInfoObj)
                 .AssertStatus(INVALID_ARGUMENT, "GetSupportedOutputCapability 1 args parse error")) {
            return nullptr;
        }
    } else if (napiArgsSize == ARGS_TWO) {
        if (!CameraNapiParamParser(env, info, cameraManagerNapi, cameraInfoObj, jsSceneMode)
                 .AssertStatus(INVALID_ARGUMENT, "GetSupportedOutputCapability 2 args parse error")) {
            return nullptr;
        }
        if (jsSceneMode == JsSceneMode::JS_NORMAL) {
            CameraNapiUtils::ThrowError(env, INVALID_ARGUMENT, "invalid js mode");
            return nullptr;
        }
    } else {
        CameraNapiUtils::ThrowError(env, INVALID_ARGUMENT, "Args size error");
        return nullptr;
    }
    return cameraManagerNapi->cameraManager_->GetCameraDeviceFromId(cameraId);
}

napi_value CameraManagerNapi::GetSupportedOutputCapability(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("GetSupportedOutputCapability is called");
    CameraManagerNapi* cameraManagerNapi = nullptr;
    int32_t jsSceneMode = JsSceneMode::JS_NORMAL;
    sptr<CameraDevice> cameraInfo =
        GetSupportedOutputCapabilityGetCameraInfo(env, info, cameraManagerNapi, jsSceneMode);

    if (cameraInfo == nullptr) {
        MEDIA_ERR_LOG("CameraManagerNapi::GetSupportedOutputCapability get camera info fail");
        CameraNapiUtils::ThrowError(env, INVALID_ARGUMENT, "Get camera info fail");
        return nullptr;
    }
    std::string cameraId = cameraInfo->GetID();
    napi_value cachedResult = GetCachedSupportedOutputCapability(env, cameraId, jsSceneMode);
    if (cachedResult != nullptr) {
        return cachedResult;
    }
    SceneMode fwkMode = SceneMode::NORMAL;
    std::unordered_map<JsSceneMode, SceneMode> jsToFwModeMap = g_jsToFwMode_;
    if (CameraNapiSecurity::CheckSystemApp(env, false)) {
        jsToFwModeMap = g_jsToFwMode4Sys_;
    }
    auto itr = jsToFwModeMap.find(static_cast<JsSceneMode>(jsSceneMode));
    if (itr != jsToFwModeMap.end()) {
        fwkMode = itr->second;
    } else {
        MEDIA_ERR_LOG("CreateCameraSessionInstance mode = %{public}d not supported", jsSceneMode);
        CameraNapiUtils::ThrowError(env, INVALID_ARGUMENT, "Not support the input mode");
        return nullptr;
    }
    auto outputCapability = cameraManagerNapi->cameraManager_->GetSupportedOutputCapability(cameraInfo, fwkMode);
    if (outputCapability == nullptr) {
        MEDIA_ERR_LOG("failed to create CreateCameraOutputCapability");
        return nullptr;
    }
    outputCapability->RemoveDuplicatesProfiles();
    GetSupportedOutputCapabilityAdaptNormalMode(fwkMode, cameraInfo, outputCapability);
    napi_value result = CameraNapiObjCameraOutputCapability(*outputCapability).GenerateNapiValue(env);
    if (cameraInfo->GetConnectionType() == CAMERA_CONNECTION_BUILT_IN) {
        CacheSupportedOutputCapability(env, cameraId, jsSceneMode, result);
    }
    return result;
}

napi_value CameraManagerNapi::IsCameraMuted(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("IsCameraMuted is called");
    napi_value result = nullptr;
    size_t argc = ARGS_ONE;
    napi_value argv[ARGS_ONE] = {0};
    napi_value thisVar = nullptr;

    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
    NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameters maximum");
    bool isMuted = CameraManager::GetInstance()->IsCameraMuted();
    MEDIA_DEBUG_LOG("IsCameraMuted : %{public}d", isMuted);
    napi_get_boolean(env, isMuted, &result);
    return result;
}

napi_value CameraManagerNapi::IsCameraMuteSupported(napi_env env, napi_callback_info info)
{
    if (!CameraNapiSecurity::CheckSystemApp(env)) {
        MEDIA_ERR_LOG("SystemApi IsCameraMuteSupported is called!");
        return nullptr;
    }
    MEDIA_INFO_LOG("IsCameraMuteSupported is called");
    napi_value result = nullptr;
    size_t argc = ARGS_ONE;
    napi_value argv[ARGS_ONE] = {0};
    napi_value thisVar = nullptr;

    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
    NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameters maximum");

    bool isMuteSupported = CameraManager::GetInstance()->IsCameraMuteSupported();
    MEDIA_DEBUG_LOG("isMuteSupported: %{public}d", isMuteSupported);
    napi_get_boolean(env, isMuteSupported, &result);
    return result;
}

napi_value CameraManagerNapi::MuteCamera(napi_env env, napi_callback_info info)
{
    if (!CameraNapiSecurity::CheckSystemApp(env)) {
        MEDIA_ERR_LOG("SystemApi MuteCamera is called!");
        return nullptr;
    }
    MEDIA_INFO_LOG("MuteCamera is called");
    napi_value result = nullptr;
    size_t argc = ARGS_TWO;
    napi_value argv[ARGS_TWO] = {0};
    napi_value thisVar = nullptr;

    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
    NAPI_ASSERT(env, argc <= ARGS_TWO, "requires 1 parameters maximum");
    bool isSupported;
    napi_get_value_bool(env, argv[PARAM0], &isSupported);
    CameraManager::GetInstance()->MuteCamera(isSupported);
    napi_get_undefined(env, &result);
    return result;
}

napi_value CameraManagerNapi::MuteCameraPersist(napi_env env, napi_callback_info info)
{
    if (!CameraNapiSecurity::CheckSystemApp(env)) {
        MEDIA_ERR_LOG("SystemApi MuteCameraPersist is called!");
        return nullptr;
    }
    MEDIA_INFO_LOG("MuteCamera is called");
    napi_value result = nullptr;
    size_t argc = ARGS_TWO;
    napi_value argv[ARGS_TWO] = {0};
    napi_value thisVar = nullptr;

    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
    NAPI_ASSERT(env, argc == ARGS_TWO, "requires 2 parameters");
    bool muteMode;
    int32_t jsPolicyType;
    napi_get_value_bool(env, argv[PARAM0], &muteMode);
    napi_get_value_int32(env, argv[PARAM1], &jsPolicyType);
    NAPI_ASSERT(env, g_jsToFwPolicyType_.count(static_cast<JsPolicyType>(jsPolicyType)) != 0,
        "invalid policyType value");
    CameraManager::GetInstance()->MuteCameraPersist(g_jsToFwPolicyType_[static_cast<JsPolicyType>(jsPolicyType)],
        muteMode);
    napi_get_undefined(env, &result);
    return result;
}

napi_value CameraManagerNapi::CreateCameraInputInstance(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("CreateCameraInputInstance is called");
    CameraManagerNapi* cameraManagerNapi = nullptr;
    size_t argSize = CameraNapiUtils::GetNapiArgs(env, info);
    sptr<CameraDevice> cameraInfo = nullptr;
    if (argSize == ARGS_ONE) {
        std::string cameraId {};
        CameraNapiObject cameraInfoObj { { { "cameraId", &cameraId } } };
        CameraNapiParamParser jsParamParser(env, info, cameraManagerNapi, cameraInfoObj);
        if (!jsParamParser.AssertStatus(INVALID_ARGUMENT, "Create cameraInput invalid argument!")) {
            MEDIA_ERR_LOG("CameraManagerNapi::CreateCameraInputInstance invalid argument");
            return nullptr;
        }
        cameraInfo = cameraManagerNapi->cameraManager_->GetCameraDeviceFromId(cameraId);
    } else if (argSize == ARGS_TWO) {
        int32_t cameraPosition;
        int32_t cameraType;
        CameraNapiParamParser jsParamParser(env, info, cameraManagerNapi, cameraPosition, cameraType);
        if (!jsParamParser.AssertStatus(INVALID_ARGUMENT, "Create cameraInput with 2 invalid arguments!")) {
            MEDIA_ERR_LOG("CameraManagerNapi::CreateCameraInputInstance 2 invalid arguments");
            return nullptr;
        }
        ProcessCameraInfo(cameraManagerNapi->cameraManager_, static_cast<const CameraPosition>(cameraPosition),
            static_cast<const CameraType>(cameraType), cameraInfo);
    } else {
        CameraNapiUtils::ThrowError(env, INVALID_ARGUMENT, "invalid argument.");
        return nullptr;
    }
    if (cameraInfo == nullptr) {
        MEDIA_ERR_LOG("cameraInfo is null");
        CameraNapiUtils::ThrowError(env, SERVICE_FATL_ERROR, "cameraInfo is null.");
        return nullptr;
    }
    sptr<CameraInput> cameraInput = nullptr;
    int retCode = cameraManagerNapi->cameraManager_->CreateCameraInput(cameraInfo, &cameraInput);
    if (!CameraNapiUtils::CheckError(env, retCode)) {
        return nullptr;
    }
    return CameraInputNapi::CreateCameraInput(env, cameraInput);
}

void CameraManagerNapi::ProcessCameraInfo(sptr<CameraManager>& cameraManager, const CameraPosition cameraPosition,
    const CameraType cameraType, sptr<CameraDevice>& cameraInfo)
{
    std::vector<sptr<CameraDevice>> cameraObjList = cameraManager->GetSupportedCameras();
    MEDIA_DEBUG_LOG("cameraInfo is null, the cameraObjList size is %{public}zu", cameraObjList.size());
    for (size_t i = 0; i < cameraObjList.size(); i++) {
        sptr<CameraDevice> cameraDevice = cameraObjList[i];
        if (cameraDevice == nullptr) {
            continue;
        }
        if (cameraDevice->GetPosition() == cameraPosition &&
            cameraDevice->GetCameraType() == cameraType) {
            cameraInfo = cameraDevice;
            break;
        }
    }
}

void CameraManagerNapi::RegisterCameraStatusCallbackListener(
    const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args, bool isOnce)
{
    if (cameraManagerCallback_ == nullptr) {
        shared_ptr<CameraManagerCallbackNapi> cameraManagerCallback =
            std::static_pointer_cast<CameraManagerCallbackNapi>(cameraManager_->GetApplicationCallback());
        if (cameraManagerCallback == nullptr) {
            cameraManagerCallback = make_shared<CameraManagerCallbackNapi>(env);
            cameraManager_->SetCallback(cameraManagerCallback);
        }
        cameraManagerCallback_ = cameraManagerCallback;
    }
    cameraManagerCallback_->SaveCallbackReference(eventName, callback, isOnce);
}

void CameraManagerNapi::UnregisterCameraStatusCallbackListener(
    const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args)
{
    if (cameraManagerCallback_ == nullptr) {
        MEDIA_ERR_LOG("cameraManagerCallback is null");
    } else {
        cameraManagerCallback_->RemoveCallbackRef(eventName, callback);
    }
}

void CameraManagerNapi::RegisterCameraMuteCallbackListener(
    const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args, bool isOnce)
{
    if (!CameraNapiSecurity::CheckSystemApp(env)) {
        MEDIA_ERR_LOG("SystemApi On cameraMute is called!");
        return;
    }
    if (cameraMuteListener_ == nullptr) {
        shared_ptr<CameraMuteListenerNapi> cameraMuteListener =
            std::static_pointer_cast<CameraMuteListenerNapi>(cameraManager_->GetCameraMuteListener());
        if (cameraMuteListener == nullptr) {
            cameraMuteListener = make_shared<CameraMuteListenerNapi>(env);
            cameraManager_->RegisterCameraMuteListener(cameraMuteListener);
        }
        cameraMuteListener_ = cameraMuteListener;
    }
    cameraMuteListener_->SaveCallbackReference(eventName, callback, isOnce);
}

void CameraManagerNapi::UnregisterCameraMuteCallbackListener(
    const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args)
{
    if (!CameraNapiSecurity::CheckSystemApp(env)) {
        MEDIA_ERR_LOG("SystemApi On cameraMute is called!");
        return;
    }
    if (cameraMuteListener_ == nullptr) {
        MEDIA_ERR_LOG("cameraMuteListener is null");
    } else {
        cameraMuteListener_->RemoveCallbackRef(eventName, callback);
    }
}

void CameraManagerNapi::RegisterTorchStatusCallbackListener(
    const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args, bool isOnce)
{
    if (torchListener_ == nullptr) {
        shared_ptr<TorchListenerNapi> torchListener =
            std::static_pointer_cast<TorchListenerNapi>(cameraManager_->GetTorchListener());
        if (torchListener == nullptr) {
            torchListener = make_shared<TorchListenerNapi>(env);
            cameraManager_->RegisterTorchListener(torchListener);
        }
        torchListener_ = torchListener;
    }
    torchListener_->SaveCallbackReference(eventName, callback, isOnce);
}

void CameraManagerNapi::UnregisterTorchStatusCallbackListener(
    const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args)
{
    if (torchListener_ == nullptr) {
        MEDIA_ERR_LOG("torchListener_ is null");
    } else {
        torchListener_->RemoveCallbackRef(eventName, callback);
    }
}

void CameraManagerNapi::RegisterFoldStatusCallbackListener(
    const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args, bool isOnce)
{
    if (foldListener_ == nullptr) {
        shared_ptr<FoldListenerNapi> foldListener =
            std::static_pointer_cast<FoldListenerNapi>(cameraManager_->GetFoldListener());
        if (foldListener == nullptr) {
            foldListener = make_shared<FoldListenerNapi>(env);
            cameraManager_->RegisterFoldListener(foldListener);
        }
        foldListener_ = foldListener;
    }
    foldListener_->SaveCallbackReference(eventName, callback, isOnce);
}

void CameraManagerNapi::UnregisterFoldStatusCallbackListener(
    const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args)
{
    if (foldListener_ == nullptr) {
        MEDIA_ERR_LOG("torchListener_ is null");
    } else {
        foldListener_->RemoveCallbackRef(eventName, callback);
    }
}

const CameraManagerNapi::EmitterFunctions& CameraManagerNapi::GetEmitterFunctions()
{
    static const EmitterFunctions funMap = {
        { "cameraStatus", {
            &CameraManagerNapi::RegisterCameraStatusCallbackListener,
            &CameraManagerNapi::UnregisterCameraStatusCallbackListener } },
        { "cameraMute", {
            &CameraManagerNapi::RegisterCameraMuteCallbackListener,
            &CameraManagerNapi::UnregisterCameraMuteCallbackListener } },
        { "torchStatusChange", {
            &CameraManagerNapi::RegisterTorchStatusCallbackListener,
            &CameraManagerNapi::UnregisterTorchStatusCallbackListener } },
        { "foldStatusChange", {
            &CameraManagerNapi::RegisterFoldStatusCallbackListener,
            &CameraManagerNapi::UnregisterFoldStatusCallbackListener } } };
    return funMap;
}

napi_value CameraManagerNapi::IsPrelaunchSupported(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("IsPrelaunchSupported is called");
    if (!CameraNapiSecurity::CheckSystemApp(env)) {
        MEDIA_ERR_LOG("SystemApi IsPrelaunchSupported is called!");
        return nullptr;
    }
    CameraManagerNapi* cameraManagerNapi = nullptr;
    std::string cameraId {};
    CameraNapiObject cameraInfoObj { { { "cameraId", &cameraId } } };
    CameraNapiParamParser jsParamParser(env, info, cameraManagerNapi, cameraInfoObj);
    if (!jsParamParser.AssertStatus(INVALID_ARGUMENT, "invalid argument!")) {
        MEDIA_ERR_LOG("CameraManagerNapi::IsPrelaunchSupported invalid argument");
        return nullptr;
    }
    sptr<CameraDevice> cameraInfo = cameraManagerNapi->cameraManager_->GetCameraDeviceFromId(cameraId);
    if (cameraInfo != nullptr) {
        bool isPrelaunchSupported = cameraManagerNapi->cameraManager_->IsPrelaunchSupported(cameraInfo);
        MEDIA_DEBUG_LOG("isPrelaunchSupported: %{public}d", isPrelaunchSupported);
        napi_value result;
        napi_get_boolean(env, isPrelaunchSupported, &result);
        return result;
    }
    MEDIA_ERR_LOG("CameraManagerNapi::IsPrelaunchSupported cameraInfo is null!");
    CameraNapiUtils::ThrowError(env, INVALID_ARGUMENT, "cameraInfo is null.");
    return nullptr;
}

napi_value CameraManagerNapi::PrelaunchCamera(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("PrelaunchCamera is called");
    if (!CameraNapiSecurity::CheckSystemApp(env)) {
        MEDIA_ERR_LOG("SystemApi PrelaunchCamera is called!");
        return nullptr;
    }
    napi_value result = nullptr;
    int32_t retCode = CameraManager::GetInstance()->PrelaunchCamera();
    if (!CameraNapiUtils::CheckError(env, retCode)) {
        return result;
    }
    MEDIA_INFO_LOG("PrelaunchCamera");
    napi_get_undefined(env, &result);
    return result;
}

napi_value CameraManagerNapi::PreSwitchCamera(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("PreSwitchCamera is called");
    if (!CameraNapiSecurity::CheckSystemApp(env)) {
        MEDIA_ERR_LOG("SystemApi PreSwitchCamera is called!");
        return nullptr;
    }
    napi_value result = nullptr;
    size_t argc = ARGS_ONE;
    napi_value argv[ARGS_ONE] = { 0 };
    napi_value thisVar = nullptr;
    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
    NAPI_ASSERT(env, argc < ARGS_TWO, "requires 1 parameters maximum");
    char buffer[PATH_MAX];
    size_t length;
    napi_get_value_string_utf8(env, argv[ARGS_ZERO], buffer, PATH_MAX, &length);
    int32_t retCode = CameraManager::GetInstance()->PreSwitchCamera(std::string(buffer));
    if (!CameraNapiUtils::CheckError(env, retCode)) {
        return result;
    }
    MEDIA_INFO_LOG("PreSwitchCamera");
    napi_get_undefined(env, &result);
    return result;
}

napi_value CameraManagerNapi::SetPrelaunchConfig(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("SetPrelaunchConfig is called");
    if (!CameraNapiSecurity::CheckSystemApp(env)) {
        MEDIA_ERR_LOG("SystemApi SetPrelaunchConfig is called!");
        return nullptr;
    }

    size_t argc = ARGS_ONE;
    napi_value argv[ARGS_ONE] = {0};
    napi_value thisVar = nullptr;
    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
    NAPI_ASSERT(env, argc < ARGS_TWO, "requires 1 parameters maximum");
    PrelaunchConfig prelaunchConfig;
    EffectParam effectParam;
    napi_value result = nullptr;

    bool isConfigSuccess = ParsePrelaunchConfig(env, argv[PARAM0], &prelaunchConfig);
    if (!isConfigSuccess) {
        MEDIA_ERR_LOG("SetPrelaunchConfig failed");
        return result;
    }
    ParseSettingParam(env, argv[PARAM0], &effectParam);
    std::string cameraId = prelaunchConfig.GetCameraDevice()->GetID();
    MEDIA_INFO_LOG("SetPrelaunchConfig cameraId = %{public}s", cameraId.c_str());

    int32_t retCode = CameraManager::GetInstance()->SetPrelaunchConfig(cameraId,
        static_cast<RestoreParamTypeOhos>(prelaunchConfig.restoreParamType), prelaunchConfig.activeTime, effectParam);
    if (!CameraNapiUtils::CheckError(env, retCode)) {
        return result;
    }
    napi_get_undefined(env, &result);
    return result;
}

napi_value CameraManagerNapi::IsTorchSupported(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("IsTorchSupported is called");
    napi_status status;
    napi_value result = nullptr;
    size_t argc = ARGS_ZERO;
    napi_value argv[ARGS_ZERO];
    napi_value thisVar = nullptr;

    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);

    napi_get_undefined(env, &result);
    CameraManagerNapi* cameraManagerNapi = nullptr;
    status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&cameraManagerNapi));
    if (status == napi_ok && cameraManagerNapi != nullptr) {
        bool isTorchSupported = CameraManager::GetInstance()->IsTorchSupported();
        MEDIA_DEBUG_LOG("IsTorchSupported : %{public}d", isTorchSupported);
        napi_get_boolean(env, isTorchSupported, &result);
    } else {
        MEDIA_ERR_LOG("IsTorchSupported call Failed!");
    }
    return result;
}

napi_value CameraManagerNapi::IsTorchModeSupported(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("IsTorchModeSupported is called");
    napi_status status;
    napi_value result = nullptr;
    size_t argc = ARGS_ONE;
    napi_value argv[ARGS_ONE];
    napi_value thisVar = nullptr;

    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);

    napi_get_undefined(env, &result);
    CameraManagerNapi* cameraManagerNapi = nullptr;
    status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&cameraManagerNapi));
    if (status == napi_ok && cameraManagerNapi != nullptr) {
        int32_t mode;
        napi_get_value_int32(env, argv[PARAM0], &mode);
        MEDIA_INFO_LOG("CameraManagerNapi::IsTorchModeSupported mode = %{public}d", mode);
        TorchMode torchMode = (TorchMode)mode;
        bool isTorchModeSupported = CameraManager::GetInstance()->IsTorchModeSupported(torchMode);
        MEDIA_DEBUG_LOG("IsTorchModeSupported : %{public}d", isTorchModeSupported);
        napi_get_boolean(env, isTorchModeSupported, &result);
    } else {
        MEDIA_ERR_LOG("GetTorchMode call Failed!");
    }
    return result;
}

napi_value CameraManagerNapi::GetTorchMode(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("GetTorchMode is called");
    CameraXCollie cameraXCollie("CameraManagerNapi::GetTorchMode");
    napi_status status;
    napi_value result = nullptr;
    size_t argc = ARGS_ZERO;
    napi_value argv[ARGS_ZERO];
    napi_value thisVar = nullptr;

    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);

    napi_get_undefined(env, &result);
    CameraManagerNapi* cameraManagerNapi = nullptr;
    status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&cameraManagerNapi));
    if (status == napi_ok && cameraManagerNapi != nullptr) {
        TorchMode torchMode = CameraManager::GetInstance()->GetTorchMode();
        MEDIA_DEBUG_LOG("GetTorchMode : %{public}d", torchMode);
        napi_create_int32(env, torchMode, &result);
    } else {
        MEDIA_ERR_LOG("GetTorchMode call Failed!");
    }
    return result;
}

napi_value CameraManagerNapi::SetTorchMode(napi_env env, napi_callback_info info)
{
    MEDIA_INFO_LOG("SetTorchMode is called");
    napi_status status;
    napi_value result = nullptr;
    size_t argc = ARGS_ONE;
    napi_value argv[ARGS_ONE];
    napi_value thisVar = nullptr;

    CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);

    napi_get_undefined(env, &result);
    CameraManagerNapi* cameraManagerNapi = nullptr;
    status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&cameraManagerNapi));
    if (status == napi_ok && cameraManagerNapi != nullptr) {
        int32_t mode;
        napi_get_value_int32(env, argv[PARAM0], &mode);
        MEDIA_INFO_LOG("CameraManagerNapi::SetTorchMode mode = %{public}d", mode);
        TorchMode torchMode = (TorchMode)mode;
        int32_t retCode = CameraManager::GetInstance()->SetTorchMode(torchMode);
        if (!CameraNapiUtils::CheckError(env, retCode)) {
            MEDIA_DEBUG_LOG("SetTorchMode fail throw error");
        }
    } else {
        MEDIA_ERR_LOG("GetTorchMode call Failed!");
    }
    return result;
}

napi_value CameraManagerNapi::On(napi_env env, napi_callback_info info)
{
    CameraXCollie cameraXCollie("CameraManagerNapi::On");
    return ListenerTemplate<CameraManagerNapi>::On(env, info);
}

napi_value CameraManagerNapi::Once(napi_env env, napi_callback_info info)
{
    return ListenerTemplate<CameraManagerNapi>::Once(env, info);
}

napi_value CameraManagerNapi::Off(napi_env env, napi_callback_info info)
{
    return ListenerTemplate<CameraManagerNapi>::Off(env, info);
}
} // namespace CameraStandard
} // namespace OHOS
